#include <asm-generic/errno-base.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include <errno.h>

#define PROCNUM 	10
#define FINEANME	"./out"
#define LINESIZE	1024

static int semid;

static void P(void)
{
	struct sembuf op;
	op.sem_num = 0;
	op.sem_op = -1;
	op.sem_flg = 0;
	// 获取一个信号量
	while (semop(semid, &op, 1) < 0) {
		if(errno != EINTR || errno != EAGAIN){
			perror("semop()");
			exit(1);
		}
	}
}

static void V(void)
{
	struct sembuf op;
	op.sem_num = 0;
	op.sem_op = 1;
	op.sem_flg = 0;
	// 释放一个信号量
	while (semop(semid, &op, 1) < 0) {
		if(errno != EINTR || errno != EAGAIN){
			perror("semop()");
			exit(1);
		}
	}
}

static void process_lockf(void)
{
	FILE *fp;
	int fd;

	char linebuf[LINESIZE];

	fp = fopen(FINEANME, "r+");
	if(fp == NULL){
		perror("fopen()");
		exit(1);
	}

	P();
	fgets(linebuf, LINESIZE, fp);
	fseek(fp, 0, SEEK_SET);
	fprintf(fp, "%d\n", atoi(linebuf) + 1);
	fflush(fp);
	V();

	fclose(fp);

}

/*
 * 文件锁
 * */
int main(int argc, char **argv)
{

	int i, pid;

	/*
	 * 创建一个信号量数组，这里是父子进程所以这里的key使用IPC_PRIVATE
	 * */
	semid = semget(IPC_PRIVATE, 1, 0600);
	if(semid < 0){
		perror("semget()");
		exit(1);
	}

	// 初始化信号量
	if(semctl(semid, 0, SETVAL, 1)){
		perror("semget()");
		exit(1);
	}

	for (i = 0; i < PROCNUM; i++) {
		pid = fork();
		if(pid < 0){
			perror("fork()");
			exit(1);
		}
		if(pid == 0){
			process_lockf();
			exit(0);
		}
	}

	for (i = 0; i < PROCNUM; i++) {
		wait(NULL);
	}

	// 销毁信号量
	semctl(semid, 0, IPC_RMID);

	exit(0);
}
